#include "shader.h"

#if defined(__APPLE__)
#	include <OpenGL/glx.h>
#elif defined(__WIN32__)
#	include <wingdi.h>
#else
#	include <GL/glx.h>
#endif

static char *readTextFile(char *fn) 
{
	FILE *fp;
	char *content = NULL;

	int count=0;

	if (fn != NULL) {

		fp = fopen(fn,"rt");

		if (fp != NULL) {
									      
    	      		fseek(fp, 0, SEEK_END);
    			count = ftell(fp);
    			rewind(fp);

			if (count > 0) {
				content = (char *)malloc(sizeof(char) * (count+1));
				count = fread(content,sizeof(char),count,fp);
				content[count] = '\0';
			}
			fclose(fp);			
		}
	}

	return content;
}

//Got this from http://www.lighthouse3d.com/opengl/glsl/index.php?oglinfo
// it prints out shader info (debugging!)
static void printShaderInfoLog(GLuint obj)
{
    int infologLength = 0;
    int charsWritten  = 0;
    char *infoLog;
    glGetShaderiv(obj, GL_INFO_LOG_LENGTH,&infologLength);
    if (infologLength > 1)
    {
        infoLog = (char *)malloc(infologLength);
        glGetShaderInfoLog(obj, infologLength, &charsWritten, infoLog);
	printf("printShaderInfoLog:\n%s\n",infoLog);
        free(infoLog);
    }else{
	printf("Shader Info Log: OK\n");
    }
}

rat_shader *rat_load_shader(char *dir,char *name,FILE *log_file)
{
	GLuint program,frag,vert;
	char frag_filename[1024];
	char vert_filename[1024];
	char *frag_source,*vert_source;
	
	program=glCreateProgram();
	
	frag=glCreateShader(GL_FRAGMENT_SHADER);
	vert=glCreateShader(GL_VERTEX_SHADER);
	
	strcpy(frag_filename,dir);
	strcat(frag_filename,"/");
	strcat(frag_filename,name);
	strcat(frag_filename,".frag");
	
	strcpy(vert_filename,dir);
	strcat(vert_filename,"/");
	strcat(vert_filename,name);
	strcat(vert_filename,".vert");
	
	frag_source=readTextFile(frag_filename);
	if (frag_source==NULL)
	{
		printf("could not load fragment program: %s\n",frag_filename);
		return NULL;
	}
	else
		printf("loaded fragment program: %s\n",frag_filename);
	vert_source=readTextFile(vert_filename);
	if (vert_source==NULL)
	{
		printf("could not load vertex program: %s\n",vert_filename);
		return NULL;
	}
	else
		printf("loaded vertex program: %s\n",vert_filename);
	
	glShaderSource(frag,1,&frag_source,NULL);
	glShaderSource(vert,1,&vert_source,NULL);
	
	free(frag_source); free(vert_source);
	
	glCompileShader(frag);
	glCompileShader(vert);
	
	glAttachShader(program,frag);
	glAttachShader(program,vert);
	
	glLinkProgram(program);
	
	printf("GPU program linked.\n");
	
	rat_shader *shader=(rat_shader *)malloc(sizeof(rat_shader));
	
	shader->dumped=0;
	shader->program_handle=program;
	shader->vert=vert; shader->frag=frag;
	shader->log=log_file;
	
	printf("shader object created.\n");
	
	return shader;
}

void rat_destroy_shader(rat_shader *shader)
{
	glDeleteProgram(shader->program_handle);
	free(shader);
	
	printf("destroyed shader object and GPU program.\n");
}

//Got this from http://www.lighthouse3d.com/opengl/glsl/index.php?oglinfo
// it prints out shader info (debugging!)
static void printProgramInfoLog(GLuint obj)
{
    int infologLength = 0;
    int charsWritten  = 0;
    char *infoLog;
    glGetProgramiv(obj, GL_INFO_LOG_LENGTH,&infologLength);
    if (infologLength > 1)
    {
        infoLog = (char *)malloc(infologLength);
        glGetProgramInfoLog(obj, infologLength, &charsWritten, infoLog);
	printf("printProgramInfoLog:\n%s\n",infoLog);
        free(infoLog);
    }else{
 	printf("Program Info Log: OK\n");
    }
}


void rat_apply_shader(rat_shader *shader)
{
	if (!shader)
		glUseProgram(0);
	else
	{
		glUseProgram(shader->program_handle);
		if (!shader->dumped)
		{
			printShaderInfoLog(shader->frag);
			printShaderInfoLog(shader->vert);
			printProgramInfoLog(shader->program_handle);
			shader->dumped=1;
		}
	}
}

